use const_primes::Primes;

const PRIMES_CACHE: Primes<10000> = Primes::new();

/// 获取前两个不满足 Goldbach 猜想的数之和
///
/// 如果该和存在, 则返回数之和, 否则返回 0
pub fn goldbach_conjecture() -> u64 {
    let mut res = 0;
    // 由 迭代器 中获取奇合数
    // 这样可以根据需要往后自动拓展
    for odd in generate_odd_composite_number() {
        if PRIMES_CACHE.iter().take_while(|&&x| x < odd as u32)
            .map(|s| *s as u32 as u64)
            .all(|p| !((odd - p) % 2 == 0 && is_same_after_sqrt((odd - p) / 2))) { 
    
            if res == 0 {
                res += odd;
            } else {
                res += odd;
                return res;
            }
        }

    };
    0
}

/// 判断 num 是否是素数
#[inline(always)]
fn is_prime(num: u64) -> bool {
    if num <= 1 {
        return false;
    }
    for i in 2..=((num as f64).sqrt() as u64) {
        if num % i == 0 {
            return false;
        }
    }
    true
}


/// 生成并返回 奇合数 的迭代器
pub fn generate_odd_composite_number() -> impl Iterator<Item = u64> {
    let mut cur: u64 = 9;
    std::iter::from_fn(move || loop {
        if cur % 2 == 1 && !is_prime(cur) {
            let res = Some(cur);
            cur += 2;
            return res;
        }
        cur += 2
    })
}

/// 精度更好的开方匹配
/// odd = primes + 2 * n.pow(2)
/// n = $\left (\sqrt{\frac{odd - primes}{2} } \right ) ^2$
#[inline]
pub fn is_same_after_sqrt(num: u64) -> bool {
    let tmp = (num as f64).sqrt() as u64;
    tmp.pow(2) == num
}

